let hideDate: number;

// 参数类型
export interface Params {
  url: string;
  isNeedHeart?: boolean;
  onError: (event: Event) => void;
  onOpen: () => void;
  onMessage?: <T>(msg: T) => void;
  onClose: (event: CloseEvent) => void;
  onLine: () => void;
  token?: string | null;
  binaryType?: BinaryType;
  onReadyStateChange?: (status: WebSocket['readyState']) => void;
}
// 监听的事件类型
type ListenFn = (args: MessageEvent) => void;
window.socketLists = [];
// WS类
export default class WS {
  static ONLINE: WS[] = [];
  ws: WebSocket | null = null;
  onError;
  onClose;
  onOpen;
  onLine;
  onReadyStateChange;
  binaryType;
  reconnectTimer: NodeJS.Timeout | null;
  url: string;
  isNeedHeart: boolean; // 是否需要心跳保活
  timeout: number;
  token: string | null;
  reGetTokenTimer: NodeJS.Timeout | null;
  socketMsgQueue: (string | ArrayBufferLike | Blob | ArrayBufferView)[];
  callbacks: Array<() => void>;
  heartBeatTimer: NodeJS.Timeout | null;
  // 监听的事件列表
  eventLists: Set<ListenFn> = new Set([]);
  // 构造器, 实例化
  constructor({
    url,
    onOpen,
    onClose,
    onLine,
    token,
    onError,
    binaryType,
    onReadyStateChange,
    isNeedHeart,
  }: Params) {
    this.onError = onError || function () {};
    this.onClose = onClose || function () {};
    this.onOpen = onOpen || function () {};
    this.onLine = onLine || function () {};
    this.url = url || '';
    this.isNeedHeart = isNeedHeart === undefined ? true : isNeedHeart;
    this.reconnectTimer = null;
    this.binaryType = binaryType;
    this.onReadyStateChange = onReadyStateChange;
    this.timeout = 5000;
    this.token = token || null;
    this.reGetTokenTimer = null;
    this.socketMsgQueue = [];
    this.callbacks = [];
    this.heartBeatTimer = null;
    this.connect();
    this.loadEvent();
  }
  // 获取readyState
  getReadyState() {
    const readyState =
      this.ws && typeof this.ws.readyState !== 'undefined'
        ? this.ws.readyState
        : 0;
    if (this.onReadyStateChange) {
      this.onReadyStateChange(readyState);
    }
  }
  // 检测设备当前状态是否正常
  isDeviceStatusOk() {
    // 联网并且可见
    return window.navigator.onLine && document.visibilityState === 'visible';
  }
  // 增加ONLINE静态属性中的ws实例
  addOnLineArr() {
    const isHad = WS.ONLINE.some(
      (socket) =>
        (socket && socket.ws && socket.ws.url) === (this.ws && this.ws.url),
    );
    if (!isHad) {
      WS.ONLINE.push(this);
    }
    window.socketLists = WS.ONLINE;
  }
  // 减少ONLINE静态属性中的ws实例
  subOnLineArr() {
    if (this.ws && this.ws.url) {
      WS.ONLINE = WS.ONLINE.filter(
        (socket) =>
          (socket && socket.ws && socket.ws.url) !== (this.ws as WebSocket).url,
      );
    }
    window.socketLists = WS.ONLINE;
  }
  // 事件部分
  loadEvent() {
    window.addEventListener('online', this.onlineFn);
    window.addEventListener('offline', this.offlineFn);
    document.addEventListener('visibilitychange', this.showScreenFn);
  }
  onlineFn = () => {
    console.log('onlineFn', this.url);
    this.connect();
    this.onLine && this.onLine();
  };
  offlineFn = () => {
    this.getReadyState();
  };
  // 显屏方法
  showScreenFn = () => {
    this.getReadyState();
    // 亮屏
    if (document.visibilityState === 'visible') {
      const now = new Date().getTime();
      const timeLen = now - hideDate;
      console.log('🚀 ~ 息屏时长', timeLen / 1000 + '秒');
      console.log('websocket此时状态', this.ws && this.ws.readyState, this.url);
      // websocket因长期熄屏断了
      if ((this.ws && this.ws.readyState !== 1) || !this.ws) {
        this.connect();
      }
      // 息屏
    } else {
      hideDate = new Date().getTime();
    }
  };
  // 卸载事件
  unloadEvent() {
    console.log('卸载事件');
    window.removeEventListener('online', this.onlineFn);
    window.removeEventListener('offline', this.offlineFn);
    document.removeEventListener('visibilitychange', this.showScreenFn);
  }
  // 重置定时器
  resetHeart() {
    this.heartBeatTimer && clearTimeout(this.heartBeatTimer);
    this.reconnectTimer && clearTimeout(this.reconnectTimer);
  }
  // 开启心跳保活
  startHeart(params?: string) {
    if (!this.isNeedHeart) return;
    this.getReadyState();
    this.resetHeart();
    this.heartBeatTimer = setTimeout(() => {
      this.send('ping');
      this.reconnectTimer = setTimeout(() => {
        // 因为没返回心跳导致中断
        if (params === 'no-pong') {
          this.connect();
          console.error(this.url + '心跳未返回, 关闭websocket');
        }
      }, this.timeout);
    }, this.timeout);
  }
  // 创建websocket实例
  createWebSocket() {
    // 全局socket列表
    if (!WS.ONLINE) {
      WS.ONLINE = [];
    }
    try {
      // let token = this.token;
      // 如果token存在
      // if (token) {
      // token = 'Bearer ' + token;
      // 兼容性校验
      if ('WebSocket' in window) {
        if (this.token) {
          this.ws = new WebSocket(this.url, [this.token]);
        } else {
          this.ws = new WebSocket(this.url);
        }
      } else {
        alert('您的浏览器暂不支持websocket');
        return;
      }
      this.addOnLineArr();
      this.ws.binaryType = this.binaryType || 'blob';
      // }
      // else {
      //   this.reGetTokenTimer && clearTimeout(this.reGetTokenTimer);
      //   this.reGetTokenTimer = setTimeout(() => {
      //     this.createWebSocket();
      //   }, 1000);
      // }
    } catch (e) {
      if (e) {
        console.log('创建websocket错误:', (e as { message: string }).message);
      }
      this.connect();
    }
  }
  // 连接
  connect(cb?: () => void) {
    // 监听网络是否正常
    if (!window.navigator.onLine) {
      alert('网络未连接！');
      return;
    }
    // 执行连接
    const doConnect = () => {
      this.createWebSocket();
      this.listenEvent();
    };
    if (!this.ws) {
      cb && this.callbacks.push(cb);
      // 首次连接
      doConnect();
      console.log('开始连接了');
    } else if (this.ws.readyState === WebSocket.OPEN) {
      console.log('websocket已经连接成功了');
      // 连接正常的情况
      cb && cb();
    } else if (this.ws.readyState === WebSocket.CONNECTING) {
      console.log('websocket正在连接中');
      cb && this.callbacks.push(cb);
    } else if (this.ws.readyState === WebSocket.CLOSING) {
      console.log('websocket正在关闭');
      cb && this.callbacks.push(cb);
      doConnect();
    } else if (this.ws.readyState === WebSocket.CLOSED) {
      console.log('websocket已经关闭');
      cb && this.callbacks.push(cb);
      doConnect();
    }
    this.getReadyState();
  }
  // 增加监听事件
  addEvent(fn: ListenFn) {
    // console.log('add', !this.eventLists.has(fn), this.eventLists);
    if (!this.eventLists.has(fn)) {
      // 增加该事件
      this.eventLists.add(fn);
    }
  }
  onMessage(msg: MessageEvent) {
    if (this.eventLists) {
      this.eventLists.forEach((fn) => {
        fn(msg);
      });
    }
  }
  // 监听消息事件
  listenMessageEvent() {
    if (!this.ws) return;
    this.ws.onmessage = (event) => {
      // 文本格式
      if (typeof event.data === 'string') {
        if (event && event.data === 'pong') {
          this.startHeart('no-pong');
        } else {
          const data = JSON.parse(event.data);
          this.onMessage && this.onMessage(data);
          console.log('websocket消息事件---->', data);
        }
        // 二进制格式
      } else if (event.data instanceof Blob) {
        // todo
        this.onMessage && this.onMessage(event);
      } else if (event.data instanceof ArrayBuffer) {
        // todo
        this.onMessage && this.onMessage(event);
      }
    };
  }
  // 监听错误/关闭等事件
  listenEvent() {
    if (!this.ws) return;
    // 连接上了
    this.ws.onopen = async () => {
      for (let i = 0; i < this.socketMsgQueue.length; i++) {
        console.log('重发数据', this.socketMsgQueue[i]);
        await this.send(this.socketMsgQueue[i]);
      }
      this.getReadyState();
      this.socketMsgQueue = [];
      this.listenMessageEvent();
      this.startHeart();
      this.onOpen();
      this.callbacks.forEach((cb) => {
        cb && console.log('🚀 ~ 执行websocket事件队列', cb);
        cb && cb();
      });
      this.callbacks.length = 0;
    };
    // 关闭/报错的情况
    // onclose 的error code返回值不稳定
    this.ws.onclose = (event) => {
      this.onClose(event);
      console.log('websocket关闭code---->', event.code);
      const isInONLINE = WS.ONLINE.some(
        (socket) =>
          (socket && socket.ws && socket.ws.url) === (this.ws && this.ws.url),
      );
      // 非正常关闭
      if (isInONLINE) {
        console.log('非正常关闭');
        this.onError(event);
        this.connect();
        // 正常关闭
      } else {
        console.log('正常关闭');
      }
      this.getReadyState();
    };
    // onerror不太稳定
    this.ws.onerror = (event: Event) => {
      this.onError(event);
      this.connect();
      this.getReadyState();
      console.error('websocket异常事件---->', event);
    };
  }
  // 发送消息
  send(json: string | ArrayBufferLike | Blob | ArrayBufferView) {
    console.log(json, 'jsonjson');
    // 发送消息必须是连接已经建立的情况下
    if (this.ws && this.ws.readyState === 1) {
      this.ws.send(json);
    } else {
      this.socketMsgQueue.push(json);
      console.log('连接尚未建立');
    }
  }
  close() {
    console.log('执行正常关闭');
    this.unloadEvent();
    this.subOnLineArr();
    this.resetHeart();
    this.ws && this.ws.close();
    this.ws = null;
  }
}

export type WSTYPE = WS;
